/* eslint-disable no-console */
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import browserSync from 'browser-sync'
import { watch } from 'chokidar'

export class BrowserSyncManager {
  /**
   * 浏览器同步服务管理器
   * @param {string | object} [config] - 配置路径或配置对象（可选）
   * @param {object} [options] - 运行时选项
   * @param {Function} [logger] - 自定义日志输出
   */
  constructor(config = {}, options = {}, logger = console.log) {
    // 初始化日志
    this.logger = logger
    this.logger('\u001B[1;35m >>> 启动浏览器同步 <<< \u001B[0m')

    // 初始化参数
    this._options = {
      autoLoadConfig: true,
      configFile: path.resolve(process.cwd(), 'bs-config.json'), // 默认配置文件
      ...options,
    }

    // 配置存储（优先级：构造函数参数 > 配置文件 > 默认值）
    this._config = {
      server: {
        baseDir: './dist',
      },
      port: 3000,
      open: false,
      notify: false,
      logLevel: 'info', // 支持 debug、error、warn、info、silent
      ...(this._loadConfig(config) || {}),
    }

    // 运行时状态
    this.bs = browserSync.create()
    this.watchers = new Map()
  }

  /**
   * 加载配置（支持文件路径或直接传入对象）
   * @private
   */
  _loadConfig(config) {
    // 如果传入的是配置对象，直接返回
    if (typeof config === 'object' && !Array.isArray(config) && config.length) {
      this.logger('加载函数参数配置')
      return config
    }

    // 自动加载配置文件逻辑
    if (this._options.autoLoadConfig) {
      const configPath = typeof config === 'string' ? config : this._options.configFile
      try {
        if (fs.existsSync(path.resolve(configPath))) {
          if (configPath.endsWith('.json')) {
            return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
          }
          else {
            throw new Error('仅支持 .json 配置文件')
          }
        }
        else {
          this.logger(`\u001B[1;33m使用默认配置文件失败，该文件不存在 - ${configPath}\u001B[0m`)
        }
      }
      catch (e) {
        console.warn(`⚠️ 配置文件加载失败: ${e.message}`)
      }
    }
    return {}
  }

  /**
   * 启动服务（支持动态覆盖配置）
   * @param {object} [overrideConfig] - 需要覆盖的配置项
   */
  start(overrideConfig = {}) {
    const finalConfig = {
      ...this._config,
      ...overrideConfig,
    }

    this.bs.init(finalConfig, (err, instance) => {
      if (err)
        throw err
      this.logger(`🚀 服务已启动: http://localhost:${instance.options.get('port')}`)
    })

    // 自动绑定文件监听
    if (finalConfig.files) {
      this.addWatch(finalConfig.files)
    }

    return this
  }

  /**
   * 添加文件监听（支持热重载）
   * @param {string | Array} patterns - 文件匹配模式
   * @param {Function} [callback] - 自定义回调
   */
  addWatch(patterns, callback) {
    const watcher = watch(patterns)
      .on('change', (path) => {
        // 默认执行文件刷新
        callback ? callback(path) : this.bs.reload(path)
      })

    this.watchers.set(patterns, watcher)
    return this
  }

  /**
   * 发送浏览器通知
   * @param {string} message - 通知内容（支持 HTML）
   * @param {number} [timeout] - 显示时长（毫秒）
   */
  notify(message, timeout = 2000) {
    this.bs.notify(message, timeout)
  }

  /**
   * 销毁实例（释放资源）
   */
  destroy() {
    // 停止所有监听器
    this.watchers.forEach(watcher => watcher.close())
    this.watchers.clear()

    // 关闭 BrowserSync 服务
    this.bs.cleanup()
    this.logger('服务已终止')
  }
}
